<?xml version="1.0" encoding="UTF-8" ?>
<!--

    Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
    under one or more contributor license agreements. See the NOTICE file
    distributed with this work for additional information regarding copyright
    ownership. Camunda licenses this file to you under the Apache License,
    Version 2.0; you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 

<mapper namespace="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity">

  <!-- AUTHORIZATION INSERT -->
  <insert id="insertAuthorization" parameterType="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity">
    insert into ${prefix}ACT_RU_AUTHORIZATION (
      ID_,
      TYPE_,
      GROUP_ID_,
      USER_ID_,
      RESOURCE_TYPE_,
      RESOURCE_ID_,
      PERMS_,
      ROOT_PROC_INST_ID_,
      REMOVAL_TIME_,
      REV_
      )
    values (
      #{id ,jdbcType=VARCHAR},
      #{authorizationType ,jdbcType=INTEGER},
      #{groupId ,jdbcType=VARCHAR},
      #{userId ,jdbcType=VARCHAR},
      #{resourceType ,jdbcType=INTEGER},
      #{resourceId ,jdbcType=VARCHAR},
      #{permissions, jdbcType=INTEGER},
      #{rootProcessInstanceId, jdbcType=VARCHAR},
      #{removalTime, jdbcType=TIMESTAMP},
      1
    )
  </insert>

  <!-- AUTHORIZATION UPDATE -->

  <update id="updateAuthorization" parameterType="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity">
    update ${prefix}ACT_RU_AUTHORIZATION set
      REV_ = #{revisionNext, jdbcType=INTEGER},
      TYPE_ = #{authorizationType, jdbcType=INTEGER},
      GROUP_ID_ = #{groupId, jdbcType=VARCHAR},
      USER_ID_ = #{userId, jdbcType=VARCHAR},
      RESOURCE_TYPE_ = #{resourceType, jdbcType=INTEGER},
      RESOURCE_ID_ = #{resourceId, jdbcType=VARCHAR},
      PERMS_ = #{permissions, jdbcType=INTEGER},
      REMOVAL_TIME_ = #{removalTime, jdbcType=TIMESTAMP},
      ROOT_PROC_INST_ID_ = #{rootProcessInstanceId, jdbcType=TIMESTAMP}
    where ID_ = #{id, jdbcType=VARCHAR}
      and REV_ = #{revision, jdbcType=INTEGER}
  </update>

  <update id="updateAuthorizationsByRootProcessInstanceId"
          parameterType="java.util.Map">
    update ${prefix}ACT_RU_AUTHORIZATION set
    REMOVAL_TIME_ = #{removalTime, jdbcType=TIMESTAMP}

    where ROOT_PROC_INST_ID_ = #{rootProcessInstanceId, jdbcType=VARCHAR}
  </update>

  <update id="updateAuthorizationsByRootProcessInstanceId_mssql"
          parameterType="java.util.Map">
    update RES set
    RES.REMOVAL_TIME_ = #{removalTime, jdbcType=TIMESTAMP}
    FROM ${prefix}ACT_RU_AUTHORIZATION RES WITH (FORCESEEK)
    where RES.ROOT_PROC_INST_ID_ = #{rootProcessInstanceId, jdbcType=VARCHAR}
  </update>

  <update id="updateAuthorizationsByProcessInstanceId"
          parameterType="java.util.Map">
    update ${prefix}ACT_RU_AUTHORIZATION set
    REMOVAL_TIME_ = #{removalTime, jdbcType=TIMESTAMP}

    where
      <!-- task instances -->
      RESOURCE_ID_ IN (
        SELECT ID_
        FROM ${prefix}ACT_HI_TASKINST
        WHERE PROC_INST_ID_ = #{processInstanceId, jdbcType=VARCHAR}
      )
      <!-- process instances -->
      or RESOURCE_ID_ = #{processInstanceId, jdbcType=VARCHAR}
  </update>

  <update id="updateAuthorizationsByProcessInstanceId_mssql"
          parameterType="java.util.Map">
    update RES set
    RES.REMOVAL_TIME_ = #{removalTime, jdbcType=TIMESTAMP}
    FROM ${prefix}ACT_RU_AUTHORIZATION RES WITH (FORCESEEK)
    where
      <!-- task instances -->
      RES.RESOURCE_ID_ IN (
        SELECT ID_
        FROM ${prefix}ACT_HI_TASKINST
        WHERE PROC_INST_ID_ = #{processInstanceId, jdbcType=VARCHAR}
      )
      <!-- process instances -->
      or RES.RESOURCE_ID_ = #{processInstanceId, jdbcType=VARCHAR}
  </update>

  <!-- AUTHORIZATION DELETE -->

  <update id="deleteAuthorization" parameterType="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity">
    DELETE FROM 
        ${prefix}ACT_RU_AUTHORIZATION 
    where
        ID_ = #{id}
        and REV_ = #{revision}
  </update>

  <delete id="deleteAuthorizationsForResourceId" parameterType="map">
    delete from ${prefix}ACT_RU_AUTHORIZATION 
    where 
        RESOURCE_TYPE_ = #{resourceType} 
        AND RESOURCE_ID_ = #{resourceId}
  </delete>

  <delete id="deleteAuthorizationsForResourceIdAndUserId" parameterType="map">
    delete from ${prefix}ACT_RU_AUTHORIZATION
    where
      RESOURCE_TYPE_ = #{resourceType}
      AND RESOURCE_ID_ = #{resourceId}
      AND USER_ID_ = #{userId}
  </delete>

  <delete id="deleteAuthorizationsForResourceIdAndGroupId" parameterType="map">
    delete from ${prefix}ACT_RU_AUTHORIZATION
    where
      RESOURCE_TYPE_ = #{resourceType}
      AND RESOURCE_ID_ = #{resourceId}
      AND GROUP_ID_ = #{groupId}
  </delete>

  <delete id="deleteAuthorizationsByRemovalTime"
          parameterType="org.camunda.bpm.engine.impl.db.ListQueryParameterObject">
    <bind name="date" value="'REMOVAL_TIME_'"/>
    <bind name="reportPeriodUnitName" value="'MINUTE'"/>
    delete ${limitBeforeWithoutOffset} from ${prefix}ACT_RU_AUTHORIZATION
    where REMOVAL_TIME_ &lt;= #{parameter.removalTime}
    <include refid="andWhereMinuteInDateBetweenSql"/>
    ${limitAfterWithoutOffset}
  </delete>

  <delete id="deleteAuthorizationsByRemovalTime_oracle"
          parameterType="org.camunda.bpm.engine.impl.db.ListQueryParameterObject">
    <bind name="date" value="'REMOVAL_TIME_'"/>
    <bind name="reportPeriodUnitName" value="'MINUTE'"/>
    delete ${limitBeforeWithoutOffset} from ${prefix}ACT_RU_AUTHORIZATION
    where REMOVAL_TIME_ &lt;= #{parameter.removalTime}
    <include refid="andWhereMinuteInDateBetweenSql_oracle"/>
    ${limitAfterWithoutOffset}
  </delete>

  <delete id="deleteAuthorizationsByRemovalTime_postgres_or_db2"
          parameterType="org.camunda.bpm.engine.impl.db.ListQueryParameterObject">
    <bind name="date" value="'REMOVAL_TIME_'"/>
    <bind name="reportPeriodUnitName" value="'MINUTE'"/>
    delete ${limitBeforeWithoutOffset} from ${prefix}ACT_RU_AUTHORIZATION
    where ID_ IN
    (SELECT ID_
    FROM ${prefix}ACT_RU_AUTHORIZATION
    WHERE REMOVAL_TIME_ &lt;= #{parameter.removalTime} <include refid="andWhereMinuteInDateBetweenSql"/>
    ${limitAfterWithoutOffset})
  </delete>

  <sql id="andWhereMinuteInDateBetweenSql">
    <if test="parameter.minuteFrom != null and parameter.minuteTo != null">
      AND ${datepart1}<include refid="org.camunda.bpm.engine.impl.persistence.entity.Commons.periodUnitFunction"/>${datepart2}${date}${datepart3}
      between #{parameter.minuteFrom, jdbcType=INTEGER} and #{parameter.minuteTo, jdbcType=INTEGER}
    </if>
  </sql>

  <sql id="andWhereMinuteInDateBetweenSql_oracle">
    <if test="parameter.minuteFrom != null and parameter.minuteTo != null">
      AND ${datepart1}${date}${datepart2}<include refid="org.camunda.bpm.engine.impl.persistence.entity.Commons.periodUnitFunction"/>${datepart3}
      between #{parameter.minuteFrom, jdbcType=INTEGER} and #{parameter.minuteTo, jdbcType=INTEGER}
    </if>
  </sql>

  <!-- AUTHORIZATION RESULTMAP -->

  <resultMap id="authorizationResultMap" type="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity">
    <id property="id" column="ID_" jdbcType="VARCHAR" />
    <result property="revision" column="REV_" jdbcType="INTEGER" />
    <result property="authorizationType" column="TYPE_" jdbcType="INTEGER" />
    <result property="groupId" column="GROUP_ID_" jdbcType="VARCHAR" />
    <result property="userId" column="USER_ID_" jdbcType="VARCHAR" />
    <result property="resourceType" column="RESOURCE_TYPE_" jdbcType="INTEGER" />
    <result property="resourceId" column="RESOURCE_ID_" jdbcType="VARCHAR" />
    <result property="removalTime" column="REMOVAL_TIME_" jdbcType="TIMESTAMP" />
    <result property="rootProcessInstanceId" column="ROOT_PROC_INST_ID_" jdbcType="VARCHAR" />
    <result property="permissions" column="PERMS_" jdbcType="INTEGER" />
  </resultMap>

  <!-- AUTHORIZATION SELECT -->

  <select id="selectAuthorizationByParameters" resultMap="authorizationResultMap">
    SELECT
        *
    FROM
        ${prefix}ACT_RU_AUTHORIZATION
    <where>
      <if test="type != null">
        TYPE_ = #{type}
      </if>
      <if test="userId != null">
        AND USER_ID_ = #{userId}
      </if>
      <if test="groupId != null">
        AND GROUP_ID_ = #{groupId}
      </if>
      <if test="resourceType != null">
        AND RESOURCE_TYPE_ = #{resourceType}
      </if>
      <if test="resourceId != null">
        AND RESOURCE_ID_ = #{resourceId}
      </if>
    </where>
  </select>

  <select id="selectAuthorizedGroupIds" resultType="string">
    SELECT distinct(A.GROUP_ID_) FROM ${prefix}ACT_RU_AUTHORIZATION A
  </select>

  <select id="selectAuthorization" resultMap="authorizationResultMap">
    select * FROM ${prefix}ACT_RU_AUTHORIZATION WHERE ID_ = #{id}
  </select>

  <select id="selectRevokeAuthorization" resultType="integer">
    SELECT
    CASE
    WHEN EXISTS
    ( SELECT ID_
      FROM ${prefix}ACT_RU_AUTHORIZATION 
      WHERE TYPE_ = 2
      AND (
        USER_ID_ IN (#{userId, jdbcType=VARCHAR}, '*')
        <if test="authGroupIds != null &amp;&amp; authGroupIds.size > 0">
        OR GROUP_ID_ IN <foreach item="item" index="index" collection="authGroupIds" open="(" separator="," close=")">#{item, jdbcType=VARCHAR}</foreach>
        </if>
      )
    ) THEN 1 ELSE 0 END ${dbSpecificDummyTable}
  </select>

  <select id="selectAuthorizationByQueryCriteria" parameterType="org.camunda.bpm.engine.impl.AuthorizationQueryImpl" resultMap="authorizationResultMap">
    <include refid="org.camunda.bpm.engine.impl.persistence.entity.Commons.bindOrderBy"/>
    ${limitBefore}
    select ${distinct} RES.* 
    ${limitBetween}
    <include refid="selectAuthorizationByQueryCriteriaSql"/>
    ${orderBy}
    ${limitAfter}
  </select>

  <select id="selectAuthorizationCountByQueryCriteria" parameterType="org.camunda.bpm.engine.impl.AuthorizationQueryImpl" resultType="long">
    ${countDistinctBeforeStart} RES.ID_ ${countDistinctBeforeEnd}
    <include refid="selectAuthorizationByQueryCriteriaSql"/>
    ${countDistinctAfterEnd}
  </select>

  <sql id="selectAuthorizationByQueryCriteriaSql">
    from ${prefix}ACT_RU_AUTHORIZATION RES

    <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheckJoin" /> 

    <where>
      <if test="id != null">
        RES.ID_ = #{id}
      </if>

      <if test="authorizationType != null">
        and RES.TYPE_ = #{authorizationType}
      </if>

      <!-- userIds -->
      <if test="userIds != null &amp;&amp; userIds.length > 0">
        and RES.USER_ID_ in
        <foreach item="item" index="index" collection="userIds"
                 open="(" separator="," close=")">
          #{item}
        </foreach>
      </if>

      <!-- groupIds -->
      <if test="groupIds != null &amp;&amp; groupIds.length > 0">
        and RES.GROUP_ID_ in
        <foreach item="item" index="index" collection="groupIds"
                 open="(" separator="," close=")">
          #{item}
        </foreach>
      </if>

      <if test="queryByResourceType">
        and RES.RESOURCE_TYPE_ = #{resourceType}
      </if>
      <if test="resourceId != null">
        and RES.RESOURCE_ID_ = #{resourceId}
      </if>
      <if test="queryByPermission">
        and ${bitand1}RES.PERMS_${bitand2}#{permission}${bitand3} = #{permission}  
      </if>

      <if test="!queryByResourceType &amp;&amp; resourcesIntersection != null &amp;&amp; resourcesIntersection.size > 0">
        and RES.RESOURCE_TYPE_ in
        <foreach item="key"
                collection="resourcesIntersection"
                open="("
                separator=","
                close=")">
          #{key.id}
        </foreach>
      </if>

      <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.queryAuthorizationCheck" />

    </where>
  </sql>

  <select id="isUserAuthorizedForResource" resultType="integer">

  <if test="permissionChecks != null &amp;&amp; permissionChecks.atomicChecks.size > 1">
    SELECT
  </if>

  <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authorizationCheck" />

  <if test="permissionChecks != null &amp;&amp; permissionChecks.atomicChecks.size > 1">
    ${dbSpecificDummyTable}
  </if>

  </select>

  <sql id="authCheck">
    SELECT
    CASE

      <!-- User GRANT -->
      <if test="permCheck.resourceIdQueryParam != null || (permCheck.resourceId != null &amp;&amp; !permCheck.resourceId.equals('*')) ">
        WHEN
          <if test="permCheck.resourceIdQueryParam != null">
          ${permCheck.resourceIdQueryParam} IN
          </if>
          <if test="permCheck.resourceId != null">
          EXISTS
          </if>
            (SELECT
                    A.RESOURCE_ID_
             FROM
                    ${prefix}ACT_RU_AUTHORIZATION A
             WHERE
                    A.TYPE_ = 1
             AND
                    A.USER_ID_ = #{authUserId, jdbcType=VARCHAR}
             AND
                    ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms,  jdbcType=INTEGER}
             AND
                    A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
             AND
                    A.RESOURCE_ID_ = <if test="permCheck.resourceIdQueryParam != null">${permCheck.resourceIdQueryParam}</if><if test="permCheck.resourceId != null">#{permCheck.resourceId, jdbcType=VARCHAR}</if>)
        THEN 1
      </if>

      <!-- User REVOKE -->
      <if test="revokeAuthorizationCheckEnabled &amp;&amp; (permCheck.resourceIdQueryParam != null || (permCheck.resourceId != null &amp;&amp; !permCheck.resourceId.equals('*'))) ">
        WHEN
          <if test="permCheck.resourceIdQueryParam != null">
          ${permCheck.resourceIdQueryParam} IN
          </if>
          <if test="permCheck.resourceId != null">
          EXISTS
          </if>
            (SELECT
                    A.RESOURCE_ID_
             FROM
                    ${prefix}ACT_RU_AUTHORIZATION A
             WHERE
                    A.TYPE_ = 2
             AND
                    A.USER_ID_ = #{authUserId, jdbcType=VARCHAR}
             AND
                    ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} != #{permCheck.perms,  jdbcType=INTEGER}
             AND
                    A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
             AND
                    A.RESOURCE_ID_ = <if test="permCheck.resourceIdQueryParam != null">${permCheck.resourceIdQueryParam}</if><if test="permCheck.resourceId != null">#{permCheck.resourceId, jdbcType=VARCHAR}</if>)
        THEN 0
      </if>

      <!-- User GRANT -->
      WHEN
        EXISTS
          (SELECT
                  ID_
           FROM
                  ${prefix}ACT_RU_AUTHORIZATION A
           WHERE
                  A.TYPE_ = 1
           AND
                  A.USER_ID_ = #{authUserId, jdbcType=VARCHAR}
           AND
                  ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms, jdbcType=INTEGER}
           AND
                  A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
           AND
                  A.RESOURCE_ID_ = '*')
        THEN 1

      <!-- User REVOKE -->
      <if test="revokeAuthorizationCheckEnabled">
      WHEN
        EXISTS
          (SELECT
                  ID_
           FROM
                  ${prefix}ACT_RU_AUTHORIZATION A
           WHERE
                  A.TYPE_ = 2
           AND
                  A.USER_ID_ = #{authUserId, jdbcType=VARCHAR}
           AND
                  ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} != #{permCheck.perms, jdbcType=INTEGER}
           AND
                  A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
           AND
                  A.RESOURCE_ID_ = '*')
      THEN 0
      </if>

      ELSE
          (
          SELECT
            CASE
              <if test="authGroupIds != null &amp;&amp; authGroupIds.size > 0">

                <!-- Group GRANTS -->
                <if test="permCheck.resourceIdQueryParam != null || (permCheck.resourceId != null &amp;&amp; !permCheck.resourceId.equals('*')) ">
                  WHEN
                    <if test="permCheck.resourceIdQueryParam != null">
                    ${permCheck.resourceIdQueryParam} IN
                    </if>
                    <if test="permCheck.resourceId != null">
                    EXISTS
                    </if>
                      (SELECT
                              A.RESOURCE_ID_
                       FROM
                              ${prefix}ACT_RU_AUTHORIZATION A
                       WHERE
                              A.TYPE_ = 1
                       AND
                              A.GROUP_ID_ IN <foreach item="item" index="index" collection="authGroupIds" open="(" separator="," close=")">#{item}</foreach>
                       AND
                              ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms,  jdbcType=INTEGER}
                       AND
                              A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                       AND
                              A.RESOURCE_ID_ = <if test="permCheck.resourceIdQueryParam != null">${permCheck.resourceIdQueryParam}</if><if test="permCheck.resourceId != null">#{permCheck.resourceId, jdbcType=VARCHAR}</if>)
                  THEN 1
                </if>

                <!-- Group REVOKES -->
                <if test="revokeAuthorizationCheckEnabled &amp;&amp; (permCheck.resourceIdQueryParam != null || (permCheck.resourceId != null &amp;&amp; !permCheck.resourceId.equals('*'))) ">
                  WHEN
                    <if test="permCheck.resourceIdQueryParam != null">
                    ${permCheck.resourceIdQueryParam} IN
                    </if>
                    <if test="permCheck.resourceId != null">
                    EXISTS
                    </if>
                      (SELECT
                              A.RESOURCE_ID_
                       FROM
                              ${prefix}ACT_RU_AUTHORIZATION A
                       WHERE
                              A.TYPE_ = 2
                       AND
                              A.GROUP_ID_ IN <foreach item="item" index="index" collection="authGroupIds" open="(" separator="," close=")">#{item}</foreach>
                       AND
                              ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} != #{permCheck.perms,  jdbcType=INTEGER}
                       AND
                              A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                       AND
                              A.RESOURCE_ID_ = <if test="permCheck.resourceIdQueryParam != null">${permCheck.resourceIdQueryParam}</if><if test="permCheck.resourceId != null">#{permCheck.resourceId, jdbcType=VARCHAR}</if>)
                  THEN 0
                </if>

                <!-- Group GRANTS -->
                WHEN
                  EXISTS
                    (SELECT
                            ID_
                     FROM
                            ${prefix}ACT_RU_AUTHORIZATION A
                     WHERE
                            A.TYPE_ = 1
                     AND
                            A.GROUP_ID_ IN <foreach item="item" index="index" collection="authGroupIds" open="(" separator="," close=")">#{item}</foreach>
                     AND
                            ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms, jdbcType=INTEGER}
                     AND
                            A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                     AND
                            A.RESOURCE_ID_ = '*')
                  THEN 1

                <!-- Group REVOKES -->
                <if test="revokeAuthorizationCheckEnabled">
                WHEN
                  EXISTS
                    (SELECT
                            ID_
                     FROM
                            ${prefix}ACT_RU_AUTHORIZATION A
                     WHERE
                            A.TYPE_ = 2
                     AND
                            A.GROUP_ID_ IN <foreach item="item" index="index" collection="authGroupIds" open="(" separator="," close=")">#{item}</foreach>
                     AND
                            ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} != #{permCheck.perms, jdbcType=INTEGER}
                     AND
                            A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                     AND
                            A.RESOURCE_ID_ = '*')
                  THEN 0
                </if>

                ELSE (
                      SELECT
                        CASE
              </if>
                          <!-- GLOBAL GRANTS -->
                          <if test="permCheck.resourceIdQueryParam != null || (permCheck.resourceId != null &amp;&amp; !permCheck.resourceId.equals('*')) ">
                            WHEN
                              <if test="permCheck.resourceIdQueryParam != null">
                              ${permCheck.resourceIdQueryParam} IN
                              </if>
                              <if test="permCheck.resourceId != null">
                              EXISTS
                              </if>
                                (SELECT
                                        A.RESOURCE_ID_
                                 FROM
                                        ${prefix}ACT_RU_AUTHORIZATION A
                                 WHERE
                                        A.TYPE_ = 0
                                 AND
                                        A.USER_ID_ = '*'
                                 AND
                                        ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms,  jdbcType=INTEGER}
                                 AND
                                        A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                                 AND
                                        A.RESOURCE_ID_ = <if test="permCheck.resourceIdQueryParam != null">${permCheck.resourceIdQueryParam}</if><if test="permCheck.resourceId != null">#{permCheck.resourceId, jdbcType=VARCHAR}</if>)
                            THEN 1
                          </if>

                          <!-- GLOBAL REVOKES -->
                          <if test="revokeAuthorizationCheckEnabled &amp;&amp; (permCheck.resourceIdQueryParam != null || (permCheck.resourceId != null &amp;&amp; !permCheck.resourceId.equals('*'))) ">
                            WHEN
                              <if test="permCheck.resourceIdQueryParam != null">
                              ${permCheck.resourceIdQueryParam} IN
                              </if>
                              <if test="permCheck.resourceId != null">
                              EXISTS
                              </if>
                                (SELECT
                                        A.RESOURCE_ID_
                                 FROM
                                        ${prefix}ACT_RU_AUTHORIZATION A
                                 WHERE
                                        A.TYPE_ = 0
                                 AND
                                        A.USER_ID_ = '*'
                                 AND
                                        ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} != #{permCheck.perms,  jdbcType=INTEGER}
                                 AND
                                        A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                                 AND
                                        A.RESOURCE_ID_ = <if test="permCheck.resourceIdQueryParam != null">${permCheck.resourceIdQueryParam}</if><if test="permCheck.resourceId != null">#{permCheck.resourceId, jdbcType=VARCHAR}</if>)
                            THEN 0
                          </if>

                          <!-- GLOBAL GRANTS -->
                          WHEN
                            EXISTS
                              (SELECT
                                      ID_
                               FROM
                                      ${prefix}ACT_RU_AUTHORIZATION A
                               WHERE
                                      A.TYPE_ = 0
                               AND
                                      A.USER_ID_ = '*'
                               AND
                                      ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms, jdbcType=INTEGER}
                               AND
                                      A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                               AND
                                      A.RESOURCE_ID_ = '*')
                            THEN 1

                          <!-- GLOBAL REVOKES -->
                          <if test="revokeAuthorizationCheckEnabled">
                          WHEN
                            EXISTS
                              (SELECT
                                      ID_
                               FROM
                                      ${prefix}ACT_RU_AUTHORIZATION A
                               WHERE
                                      A.TYPE_ = 0
                               AND
                                      A.USER_ID_ = '*'
                               AND
                                      ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} != #{permCheck.perms, jdbcType=INTEGER}
                               AND
                                      A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER}
                               AND
                                      A.RESOURCE_ID_ = '*')
                            THEN 0
                          </if>

                          <!-- No matching authorization found: request is not authorized -->
                          ELSE
                          <if test="permCheck.authorizationNotFoundReturnValue != null">
                            ${permCheck.authorizationNotFoundReturnValue}
                          </if>
                          <if test="permCheck.authorizationNotFoundReturnValue == null">
                            null
                          </if>

              <if test="authGroupIds != null &amp;&amp; authGroupIds.size > 0">
                        END ${dbSpecificDummyTable}
                )
              </if>
            END ${dbSpecificDummyTable}
      )
    END  ${dbSpecificDummyTable}
  </sql>

  <!-- reusable authorization check for queries. -->
  <sql id="queryAuthorizationCheck">
      <if test="authCheck.shouldPerformAuthorizatioCheck &amp;&amp; authCheck.authUserId != null">    
        AND <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.queryAuthorizationCheckWithoutPrefix"/>
      </if>
  </sql>
  
  <sql id="queryAuthorizationCheckWithoutPrefix">
      <if test="authCheck.shouldPerformAuthorizatioCheck &amp;&amp; authCheck.authUserId != null">
        <choose>
          <when test="authCheck.revokeAuthorizationCheckEnabled">
            <bind name="permissionChecks" value="authCheck.permissionChecks" />
            <bind name="authUserId" value="authCheck.authUserId" />
            <bind name="authGroupIds" value="authCheck.authGroupIds" />        
            <bind name="revokeAuthorizationCheckEnabled" value="authCheck.revokeAuthorizationCheckEnabled" />
            (<include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authorizationCheck" />) = 1
          </when> 
          <otherwise>
            AUTH.RESOURCE_ID_ IS NOT NULL 
            <if test="authCheck.permissionChecks.compositeChecks != null &amp;&amp; authCheck.permissionChecks.compositeChecks.size > 0"> 
              AND
              <foreach item="permCheck" index="index" collection="authCheck.permissionChecks.compositeChecks" separator="AND">
                <if test="index > 0">
                  AUTH${index}.RESOURCE_ID_ IS NOT NULL
                </if>
              </foreach>
            </if>
          </otherwise>
        </choose>
    </if>
  </sql>
  
  <!-- reusable single authorization check for queries. -->
  <sql id="querySingleAuthorizationCheck">
    <if test="authCheck.shouldPerformAuthorizatioCheck &amp;&amp; authCheck.authUserId != null">

        <bind name="authUserId" value="authCheck.authUserId" />
        <bind name="authGroupIds" value="authCheck.authGroupIds" />
        <bind name="permCheck" value="authCheck.permissionChecks.atomicChecks[0]" />
        <bind name="revokeAuthorizationCheckEnabled" value="authCheck.revokeAuthorizationCheckEnabled" />
        (<include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheck" />) = 1
    </if>
  </sql>

  <!-- 
    input: "permissionChecks": an instance of CompositePermissionCheck
  
    limitation 1: can only handle at most two levels of composition (e.g. "(a or b) and (c or d)"); 
      more levels are currently not implemented because MyBatis cannot process circular include statements
      
   limitation 2: can only a CompositePermissionCheck instance that contains atomic checks or composite cheks,
     not a mixture of both (i.e. if you need "a or (b and c)", wrap "a" in another CompositePermissionCheck 
  -->
  <sql id="authorizationCheck">
    <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.atomicChecks" />
    <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.compositeChecks" />
  </sql>
  
  
  <sql id="authCheckJoin">
    <if test="authCheck.shouldPerformAuthorizatioCheck &amp;&amp; !authCheck.revokeAuthorizationCheckEnabled &amp;&amp; authCheck.authUserId != null">      
      <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheckJoinWithoutOnClause" />
      AUTH ON (AUTH.RESOURCE_ID_ ${authJoinStart} RES.ID_ ${authJoinSeparator} '*' ${authJoinEnd})
    </if>    
  </sql>
  
  
  <sql id="authCheckJoinWithoutOnClause">
    <bind name="authGroupIds" value="authCheck.authGroupIds" />
    <bind name="atomicChecks" value="authCheck.permissionChecks.atomicChecks" />
    <bind name="disjunctive" value="authCheck.permissionChecks.disjunctive" />
    <bind name="useLeftJoin" value="authCheck.useLeftJoin" />
    <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheckJoinWithoutOnClauseWithBinding" />
  </sql>

  <sql id="authCheckJoinWithoutOnClauseWithBinding">
    <choose>
      <when test="useLeftJoin != null &amp;&amp; useLeftJoin == true">left join</when>
      <otherwise>inner join</otherwise>
    </choose>
    (
    SELECT A.*
    FROM ${prefix}ACT_RU_AUTHORIZATION A
    WHERE A.TYPE_ &lt; 2     
    AND ( A.USER_ID_ in ( #{authCheck.authUserId, jdbcType=VARCHAR}, '*')           
    <if test="authGroupIds != null &amp;&amp; authGroupIds.size > 0">
      OR A.GROUP_ID_ IN <foreach item="item" index="index" collection="authGroupIds" open="(" separator="," close=")">#{item}</foreach>
    </if>
    )
    <if test="atomicChecks != null &amp;&amp; atomicChecks.size > 0">
      AND (
      <if test="disjunctive">
        <foreach item="permCheck" index="index" collection="atomicChecks" open="(" separator="OR" close=")">
          A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER} AND ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms,  jdbcType=INTEGER}
        </foreach>
      </if>
      <if test="!disjunctive">
        <foreach item="permCheck" index="index" collection="atomicChecks" open="(" separator="AND" close=")">
          A.RESOURCE_TYPE_ = #{permCheck.resourceType, jdbcType=INTEGER} AND ${bitand1}A.PERMS_${bitand2}#{permCheck.perms, jdbcType=INTEGER}${bitand3} = #{permCheck.perms,  jdbcType=INTEGER}
        </foreach>
      </if>
      )
    </if>  
    )
  </sql>

  <!-- 
   input: "permissionChecks": an instance of CompositePermissionCheck
  -->
  <sql id="atomicChecks">
    <if test="permissionChecks.atomicChecks != null &amp;&amp; permissionChecks.atomicChecks.size == 1">

      <bind name="permCheck" value="permissionChecks.atomicChecks[0]" />
      <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheck"/>

    </if>

    <if test="permissionChecks.atomicChecks != null &amp;&amp; permissionChecks.atomicChecks.size > 1">
      <if test="permissionChecks.disjunctive">
        <bind name="atomicChecks" value="permissionChecks.atomicChecks" />
        <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.disjunctiveAtomicChecks" />
      </if>
      <if test="!permissionChecks.disjunctive">
        <bind name="atomicChecks" value="permissionChecks.atomicChecks" />
        <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.conjunctiveAtomicChecks" />
      </if>
    </if>
  </sql>
  
  <!-- 
   input: "permissionChecks": an instance of CompositePermissionCheck
  -->
  <sql id="compositeChecks">
    <if test="permissionChecks.compositeChecks != null &amp;&amp; permissionChecks.compositeChecks.size > 1">
      <if test="permissionChecks.disjunctive">
        <bind name="compositeChecks" value="permissionChecks.compositeChecks" />
        <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.disjunctiveCompositeChecks"/>
      </if>
      <if test="!permissionChecks.disjunctive">
        <bind name="compositeChecks" value="permissionChecks.compositeChecks" />
        <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.conjunctiveCompositeChecks"/>
      </if>
    </if>
  </sql>
  
  <!-- 
   input: "atomicChecks": list of PermissionCheck objects
  -->
  <sql id="disjunctiveAtomicChecks">
    <foreach item="permCheck" index="index" collection="atomicChecks" separator=",">
      ${dbSpecificIfNullFunction}((<include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheck"/>)
    </foreach>
    , 0
    <foreach item="permCheck" index="index" collection="atomicChecks">
      )
    </foreach>
  </sql>
  
  <!-- 
   input: "compositeChecks": a list of CompositePermissionCheck objects
  -->
  <sql id="disjunctiveCompositeChecks">
    <foreach item="permissionChecks" index="index" collection="compositeChecks" separator=",">
      ${dbSpecificIfNullFunction}((<include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.atomicChecks" />)
    </foreach>
    , 0
    <foreach item="permissionChecks" index="index" collection="compositeChecks">
      )
    </foreach> 
  </sql>
  
  <!-- 
   input: "atomicChecks": list of PermissionCheck objects
  -->
  <sql id="conjunctiveAtomicChecks">
    <!-- the BITAND function on databases like Oracle and DB2 takes exactly two arguments;
    Instead of BITAND(a, b, c), we generate BITAND(BITAND(a, b), c)) instead -->
    <foreach index="index" collection="atomicChecks">
      <if test="index &lt; atomicChecks.size - 1">
        ${bitand1}
      </if>
    </foreach>
    <foreach  item="permCheck" index="i" collection="atomicChecks">
      ${dbSpecificIfNullFunction}(
        (<include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authCheck"/>)
      , 0)
      <if test="i &gt; 0">
        ${bitand3}
      </if>
      <if test="i &lt; atomicChecks.size - 1">
        ${bitand2}
      </if>
    </foreach>
  </sql>
  
  <!-- 
   input: "compositeChecks": a list of CompositePermissionCheck objects
  -->
  <sql id="conjunctiveCompositeChecks">
    <!-- the BITAND function on databases like Oracle and DB2 takes exactly two arguments;
    Instead of BITAND(a, b, c), we generate BITAND(BITAND(a, b), c)) instead -->
    <foreach index="index" collection="compositeChecks">
      <if test="index &lt; compositeChecks.size - 1">
        ${bitand1}
      </if>
    </foreach>
    <foreach  item="permissionChecks" index="i" collection="compositeChecks">
      <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.atomicChecks" />
      <if test="i &gt; 0">
        ${bitand3}
      </if>
      <if test="i &lt; compositeChecks.size - 1">
        ${bitand2}
      </if>
    </foreach>
  </sql>

  <sql id="contextualAuthorizationCheck">
    <if test="authCheck.shouldPerformAuthorizatioCheck &amp;&amp; authCheck.authUserId != null">
      <choose>
        <when test="authCheck.revokeAuthorizationCheckEnabled">    
          <bind name="authUserId" value="authCheck.authUserId" />
          <bind name="authGroupIds" value="authCheck.authGroupIds" />
          <bind name="revokeAuthorizationCheckEnabled" value="authCheck.revokeAuthorizationCheckEnabled" />              
          AND
          ( CASE          
          WHEN
          <!-- variable instance or task exists in context of a case instance -->
          RES.CASE_EXECUTION_ID_ is not null
          THEN
          <!-- everything which exists in context of a case instance is visible to the users -->
          1
          ELSE
          <!-- EVERYTHING ELSE like standalone tasks and other -->
          (
          <bind name="permissionChecks" value="authCheck.permissionChecks" />
          <include refid="org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity.authorizationCheck" />
          )
          END ) = 1
        </when>
        <otherwise>
          and (
          <!-- Task query does not use left join if cmmn is disabled, 
            so we don't need to account for case tasks in this case. -->
          <if test="applyAuthorizationCheckForCaseInstances" >
            (RES.CASE_EXECUTION_ID_ IS NOT NULL)
            OR
          </if>
            (AUTH.RESOURCE_ID_ IS NOT NULL)
            <if test="authCheck.permissionChecks.compositeChecks != null &amp;&amp; authCheck.permissionChecks.compositeChecks.size > 0"> 
              AND
              <foreach item="permCheck" index="index" collection="authCheck.permissionChecks.compositeChecks" separator="AND">
                <if test="index > 0">
                  AUTH${index}.RESOURCE_ID_ IS NOT NULL
                </if>
              </foreach>
            </if>
          )
        </otherwise>
      </choose>
    </if>
  </sql>
</mapper>
